<?php
include_once 'Retriever.php';
include_once '../Model/StepAtRoute.php';
include_once '../Model/Location.php';
include_once '../Utility/simplehtmldom/simple_html_dom.php';
include_once '../Exceptions/MuchParametersException.php';
include_once '../Exceptions/CommunicationException.php';

/**
 * 
 * @author Laura Magrini
 *
 */

class ACRoutePlanner extends Retriever {
	const BY_CAR = 0;
	const BY_PUBLIC_TRANSPORT = 1;
	const BY_PUBLIC_AND_CAR = 2;
	const BY_NO_METRO_NO_TRAIN = 3;
	const BY_PUBLIC_TRANSPORT_AND_BIKE = 4;
	
	const OPT_QUICKEST = 0;
	const OPT_LESS_CHANGES = 1;
	const OPT_LESS_WALK = 2;
	
	private static $NAV = '3';
	private static $ACTION_FOR_PATH_ID = 'dettaglio';
	
	private $atacURL;
	private $params;
	private $city;
	private $serviceName;
	private $separator;
	private $plus;
	private $steps;
	private $descs;
	
	function __construct() {
		$this->plus = '+';
		$this->separator = '&';
		$this->serviceName = 'percorso';
		$this->city = 'Roma';
		$this->atacURL = "http://muovi.roma.it/percorso/?";
		
		$this->params = array('start_address'=>null,
		'start_place'=>$this->city,
		'stop_address'=>null,
		'quando'=>0,
		//'stop_place'=>$this->city,
		//'service'=>$this->serviceName,
		//'action'=>'submit',
		//'nav'=>2,
		'mezzo'=>1,
		'hour'=>15,
		'minute'=>43,
		'piedi'=>1,
		'max_distanza_bici'=>'5.0',
		'bus'=>'on',
		'metro'=>'on',
		'fc'=>'on',
		'fr'=>'on',
		'Submit'=>'Calcola'
		);
		
		$this->paramsWithStopID = array(
			'id_linea'=>null,
			'service'=> 'paline',
			'action'=> 'dettaglio_linea',
			'nav'=> 2,
			'Submit' => 'Invia'
		);
				
		$this->steps = null;
	}
	
		
	/**
	 * Rende il percorso dal punto $here al punto $there ottenuto
	 * con le opzioni di default (mezzo pubblico, pi� veloce)
	 * @param unknown_type $here
	 * @param unknown_type $there
	 * @return unknown_type
	 */
	function getPathFromHereToThere($step) {
	   if ($step instanceOf StepRoute)
		{	
			unset($this->steps);
			$this->steps = null;
			$here = $step->getstart();
			$there = $step->getend();
			if (($here instanceOf Location) && ($there instanceOf Location))
			{
			//Riempio il vettore dei parametri
				$this->params['mezzo'] = $step->getmezzo();
				//$this->params['day'] = $step->getdd();
				//$this->params['month'] = $step->getmo();
				//$this->params['year'] = $step->getyy();
				$this->params['hour'] = $step->gethh();
				$this->params['minute'] = $step->getmin();
			
				$this->params['start_address'] = $here->getAddress();
				$this->params['stop_address'] = $there->getAddress();
			
				$this->params['start_address'] = str_replace(" ", "+", $this->params['start_address']);
				$this->params['stop_address'] = str_replace(" ", "+", $this->params['stop_address']);
			
			
			//Costruisco l'url con i parametri giusti
				$url= $this->atacURL;
				$flag=1;
				foreach($this->params as $key => $value)
				if($flag){
					$flag=0;
					$url.=$key."=".$value;
				}
				else
					$url = $url."&".$key."=".$value;
					
				$pageContent = $this->getHTMLPageFromURL($url); //si trova nella classe Retriever.php				
				if ($pageContent==false)
				{
					return null;
				}	
				$html = str_get_html($pageContent);		//prendo il codice html della pagina
				$text = $html->plaintext; //prendo la pagina in formato testo
				
				//print $text;
								
			//verifico la presenza di errori
				$pos = strpos($text,"servizio");
				$pos2 = strpos($text,"attivo");
				$pos3 = strpos($text,"non");

			//Il problema riguarda l'intero servizio
				if(($pos==true) && ($pos2==true) && ($pos3==true)) {
 					throw new CommunicationException ("ACRoutePlanner: No Response from ATAC", 0);
					return null;
				}
			
			//Il problema riguarda solo quella richiesta
				if ((strpos($text, "tecnici")==true) && ((strpos($text, "problemi")==true))) {
					throw new CommunicationException ("ACRoutePlanner: Service Not Available", 0);
					return null;
				}
				if ((strpos($text, "Correggi")==true) && ((strpos($text, "(molti trovati)")==true))) {									
					throw new MuchParametersException($pageContent);
					return null;
				}	
				
			//comincio a cercare i tag giusti per determinare il percorso
			/*$ret0 = $html->find('div[class=banda0]');

			if ($ret0 == null)
			{
				//Libero memoria e rendo null
				unset($ret0);
				$html->clear();
				unset($html);
				return null;
			}
			//prendo il contenuto della prima descrizione
			$this->addStepToList($this->strToPathObject($ret0[0], $step));
			$ret0[0]->clear();
			unset($ret0[0]);
			unset($ret0);
			
			
			//� necessario prendere i valori nello stesso ordine 
			//in cui vengono restituiti da atac
			$ret1 = $html->find('div[class=banda1]');
			$ret2 = $html->find('div[class=banda2]');*/
			$ret0 = $html->find('p');
			$tempi=$ret0[1]; //contiene distanza e tempo di percorrenza
			$tempi = $tempi->plaintext;
			$parts = explode("\n",$tempi);
			$time='';
			$meters='';
			
			for($i=0; $i<count($parts);$i++){
				$parts[$i]=trim($parts[$i]);
				$durata = explode("Durata spostamento: ",$parts[$i]);
				
				if(count($durata)>1){
					$time=trim($durata[1]);
					$ora=explode("ora",$time);
					if(count($ora)>1){
						$ore=trim($ora[0]);
						$minuti=explode("minuti",$ora[1]);
						$time=(int)(trim($minuti[0]))+(int)($ore*60)." minuti";
					}	
				}
				$distanza = explode("Distanza percorsa: ",$parts[$i]);
				//print_r($distanza);
				if(count($distanza)>1){
					$meters=trim($distanza[1]);
					$distanza=explode("km",$meters);
					//print_r($distanza);
					if(count($distanza)>1){
						$meters=floatval(trim($distanza[0]))*1000;
					/*	$dist=trim($distanza[0]);
						$metri=explode("metri",$dist[1]);
						$meters=(int)(trim($metri[0]))+(int)($dist*60)." metri";*/
					}
				}				
			}
			$ret0[0]->clear();
			unset($ret0);
			
						$meters.= " metri";

			
			$ret1 = $html->find('tr[class=nodo]');
			$ret2 = $html->find('tr[class=tratto]');
			$conta1=count($ret1); //numero di banda1
			$conta2=count($ret2); //numero di banda2
			
			//il numero di tratti non puo mai essere > del numero di nodi
				for($i=0;$i<$conta1;$i++){
					if($ret1[$i]!=null){
						if($i==($conta1-1))$this->addStepToList($this->strToPathObject($ret1[$i],$step, $time, $meters));
						else $this->addStepToList($this->strToPathObject($ret1[$i],$step, null, null));
						$ret1[$i]->clear();
					}
					if($i<$conta2){
						if($ret2[$i]!=null){
							$this->addStepToList($this->strToPathObject($ret2[$i],$step, null,null));
							$ret2[$i]->clear();
						}
					}
				}
				
			unset($ret1);
			unset($ret2);
			
			
			$html->clear();
			unset($html);
			return $this->steps;		
		}
		else
			throw new Exception ("ACRoutePlanner.getPathFromHereToThere: Parameters MUST be Location type");
	}else
			throw new Exception ("ACRoutePlanner.getPathFromHereToThere: Parameters MUST be StepRoute type");
		
	}
	
	private function muchaddress($html){
		$ret0 = $html->find('option[value=');
		$conta1=count($ret0);
		echo $conta1;
	}
	
	
	private function strToPathObject($rawStr, $stepRoute, $tempo, $metri) {
		$res = $rawStr->find('a');
		
		if (isset($res[0])) // tag a presente
		{
			$href = $res[0]; //memorizzo l'href che contiene la mappa
		}
		else { //non � presente il tag 'a' quindi non posso trovare informazioni
			return null;
		}
		$str = $rawStr->plaintext;
		$str=str_replace("&#39;", "'", $str);
		
		$parts = explode("(Mappa)",$str);
		$line = ltrim($parts[0]);
		$parts = explode("\n",$line);
		
		$parts_final=array();
		for($i=0; $i<count($parts);$i++){
			$desc=trim($parts[$i]);
			if(empty($desc)) continue;
			array_push($parts_final, $desc);
		}
		$parts=$parts_final;
		$line=trim($parts[0]);
		
		$i=1; //indice di inizio per le descrizioni
		$pos = strpos($line,':'); //non devo considerare l'orario iniziale
		if($pos==true){
			$line=$parts[1];
			$i=2;
		}
		$palina=null;
		$stopID=null;
				
		if (stristr($line, "Fermata")){
			$line="Recarsi alla fermata ";
		}else if (stristr($line, "A piedi")){
			$line="A piedi per ";
		}else if (stristr($line, "Metro")){
			$line="Prendere la ".$line;
		}		
		
		for($i; $i<count($parts);$i++){
			
			$parts[$i]=trim($parts[$i]);
			if(empty($parts[$i]) || stristr($parts[$i], "(Escludi)")) continue;
						
			/*if (stristr($line, "Fermata)")) //se è presente Palina prendo solo i dati che la precedono e la seguono
			{	
				$i=$i+2;
				
				while(trim($parts[$i])==null || trim($parts[$i])=="" || trim($parts[$i])==" ") $i++;
				$parts[$i]=str_replace("(partenza )","",$parts[$i]);//se trovo una partenza senza orario pulisco la stringa
				$palina.=" ".trim($parts[$i]);
				$i++;
				
				while(trim($parts[$i])==null || trim($parts[$i])=="" || trim($parts[$i])==" ") $i++;
				$parts[$i]=str_replace("(partenza )","",$parts[$i]);
				$palina.=" ".trim($parts[$i]);
				
				$palina = ltrim($palina);

			}
			
			if (stristr($parts[$i], "Durata spostamento: ")){
				$app = explode("Durata spostamento:",$parts[$i]);
				$tempo = $app[1];
				unset($app);
			}
			else if (stristr($parts[$i], "Distanza percorsa: ")){
				$app = explode("Distanza percorsa: ",$parts[$i]);
				$metri = $app[1];
				unset($app);
			}
			else{
				$this->addDescToStep($parts[$i]);	
			}*/
			$this->addDescToStep($parts[$i]);
		}
		
		/***
		fix per iPhone: si aspetta una stringa con i ':', quindi devo ricrearla
		***/
		
		if(empty($this->descs)){ //sono nel primo o nell'ultimo step
			$newline="Indirizzo: ".$line;
		}
		else if($line=='Linea'){ //sono in uno step del tipo "Linea xxx per n fermate
			$newline= "Prendere la linea: ".$this->descs[0]." ".$this->descs[1];
			$newdesc="";
			$index=0;
			if(count($this->descs)>2){
				for($i=2; $i<count($this->descs); $i++)
					$newdesc.=$this->descs[$i]." ";
			}

		}
		else{ //caso step generico
			$newline=$line.": ";
			$newdesc="";
			$index=0;
			if(count($this->descs)>0){
				foreach($this->descs as $d){
					if($index==0)
						$newline.= "$d\n";
					else
						$newdesc.=$d." ";
					$index++;	
				}
			}
		}
		
		if(!empty($newdesc))
			$newdesc=array($newdesc); //creo un array con una sognola descrizione
		else
			$newdesc=array();
			
		$step = new StepAtRoute($newline, $newdesc, $palina, $tempo, $metri, $stopID);
		
		//$step = new StepAtRoute($line, $this->descs, $palina, $tempo, $metri, $stopID);

		unset($this->descs);
		$this->descs=null;
		return $step;
	}
	
	private function addDescToStep($desc) {
		if (($desc != null) && ($desc != " ") && ($desc != "\n"))
		{
			if ($this->descs==null)
			{
				$this->descs = array($desc);	
			}
			else
				array_push($this->descs,$desc);
		}
	}
	
	private function addStepToList($step) {
		
		if ($step instanceOf StepAtRoute)
		{
		
			if ($this->steps==null)
			{
				$this->steps = array($step);	
			}
			else
				array_push($this->steps,$step);
		}
		else
			throw new WrongParametersException("Class: ACRoutePlanner. Method: addStepToList($step). 
			Parameter must be StepRoute type");
	}
	
	
	function getPathFromHereToThereWithOptions($step) {
			//funzione per il percorso con opzioni settate
	}
	
	function getPathIDForLineNumber($lineNumber, $direzione) {
		
			$infoManager = new InfoManager();
			
			$pathID = $infoManager->getPathIDForLineAndDirection($lineNumber, $direzione);//array di oggetti busstop
			return $pathID;
			
	}
	
	function getStopIDForLineNumber($pathid, $descrizione) {
		
			$infoManager = new InfoManager();
			$descrizione=explode(": ",$descrizione);
			$stopname=$descrizione[1];	
			$path = $infoManager->getCachedPath($pathid); //array di oggetti busstop
			if(count($path)>0){
				$stops=$path->getStops();
				for ($contatore=0; $contatore < count($stops); $contatore++) {
					if(strcmp($stops[$contatore]->getStopName(), $stopname)==0){
						return $stops[$contatore]->getAtacID();
					}
				}
			}
			return null;
			
	}
	
	
}



?>